package com.bitoon.basketdudes.ws;

import com.bitoon.basketdudes.jpa.Usuario;
import com.bitoon.basketdudes.jpa.Pais;
import com.bitoon.basketdudes.jpa.Region;
import com.bitoon.basketdudes.jpa.PartnerUsuario;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.sql.BatchUpdateException;
import java.sql.SQLException;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

/**
 * @author paco
 * 
 * Funciones de apoyo para integración con Arkarena
 */
public class Arkarena {

    Logger      m_log = Logger.getLogger(Arkarena.class);  
    String      m_nick_remoto;
    Usuario     m_usuario;

    // Hace el login contra un php, este php es el que realiza la llamada al webservice de login de arkarena
    // la ruta de este php se encuentra en config.properties en la entrada: arkarena.ruta
    //
    // Ejemplo de respuesta:
    // <?xml version="1.0" encoding="UTF-8"?>
    // <result>
    // <status>0</status>
    // <username>basket_ufuk</username>
    // <userid>5</userid>
    // </result>    
    //
    // Si el userid no existe en la tabla partner_usuario se considera cuenta de usuario nueva.
    // Si el userid existe en partner_usuario se actualizará el email_remoto en caso de ser diferente.
    //
    // Parámetros de Salida:
    // el parametro p_usuario si el retorno es correcto devolverá
    //     los datos del usuario registrado.
    // el parámetro p_nick_remoto contendrá el nick en el extremo de arkarena
    //     se llamará a un webservice para actualizarlo en caso de que sea diferente al nuestro.
    // Retorno: 
    // -1 - error desconocido
    // -2 - error durante la consulta externa
    // -3 - el login o contraseña son incorrectos
    // -9 - el login es correcto pero es la primera vez que accede a BD
    //      es necesario el registro de la cuenta.
    int login ( EntityManager em, String p_email, 
                String p_password, String p_location, HttpServletRequest p_request ) {
        PartnerUsuario  pu=null;
        int             retorno = -1;
        // 14/05/2013 para evitar emails en minúsculas
        String          email=p_email.toLowerCase();        
        m_nick_remoto="";

        m_log.debug(" LOGIN ARKARENA" + email);
    
        // llamo al php de raul
        HttpURLConnection   huc     =null;

        try {
            // Hacemos una llamada a los WS de Marca
            String theXMLMessage = null;

            String urlParameters = "email="+email+"&password="+p_password;
            
            // 2013/07/04 pasamos la ip del cliente al php para que la mande a Arkarena
            urlParameters+="&ip_client="+p_request.getRemoteAddr();
            // 2013/07/04 pasamos la ip del cliente al php para que la mande a Arkarena
m_log.debug("[DEBUG][ArkarenaPHP.Login]: " + urlParameters );

            URL    url           = new URL(p_location);
            huc = (HttpURLConnection)url.openConnection();
            huc.setRequestMethod("POST");
            huc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            huc.setRequestProperty("charset", "utf-8");
            huc.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length));
            huc.setUseCaches (false);
            huc.setDoOutput(true);
            huc.setDoInput(true);
            huc.setInstanceFollowRedirects(false);

            DataOutputStream wr = new DataOutputStream(huc.getOutputStream ());
            wr.writeBytes(urlParameters);
            wr.flush();
            wr.close();

            SAXBuilder parser = new SAXBuilder();
            Document   doc    = parser.build(huc.getInputStream());

            String  url2    = doc.getRootElement().getValue();
            
            Integer valido = Integer.parseInt(doc.getRootElement().getChildText("status"));

            String  desc_error=null;
            Integer user_arkarena_id=0;
            if ( valido == 1 ) {
                user_arkarena_id = Integer.parseInt(doc.getRootElement().getChildText("userid"));
                String username = doc.getRootElement().getChildText("username");
                m_nick_remoto = username;
                m_log.debug("[DEBUG][MarcaCom.Login 4]: " + user_arkarena_id + " " + username);
                try {
                    try {
                        // Si la respuesta es correcta buscamos al usuario de Arkarena
                        // para localizar al usuario de BasketDudes que le corresponde
                        Query qv = em.createNamedQuery("PartnerUsuario.findByRemoteId");
                        qv.setParameter("partner_id", (short) 2);
                        qv.setParameter("remote_id", user_arkarena_id );

                        pu = (PartnerUsuario)qv.getSingleResult();                    
                        
                        if  (pu.getRemoteEmail().compareTo(email)!= 0 ) {
                            pu.setRemoteEmail(email);
                            em.persist(pu);
                        }
                        retorno=0;
                    } catch ( NoResultException nores) {
                        // Si no existe remote_id y nos manda un nick deseado intentamos registrarle
                        
                        if (p_request.getParameter("nick")!= null && p_request.getParameter("nick").length()>2 ) {
                           
                            pu = new PartnerUsuario();
                            retorno = nuevoUsuario ( em,  username,
                                           email, user_arkarena_id, p_request, pu );
                        } else {
                            // Si no existe remote_id devolvemos que se registre
                            retorno = -9;
                        }
                    }
                    // Si el email guardado es diferente del email de login, lo actualizamos
                    if ( retorno==0 && pu != null ) {
                        m_usuario = pu.getUsuario();
                    }
                } catch (NoResultException nre) {
                    // Si no existe remote_id devolvemos que se registre
                    retorno = -9;
                    m_log.error("[Usuario correcto en Arkarena pero no existe en Basketdudes]: " +email, nre);
                }
            } else {
                if ( valido == 0 ) {
                    retorno = -3;
                } else {
                    retorno = valido;
                }
                desc_error = doc.getRootElement().getChildText("error");
                m_log.debug("[DEBUG][Arkarena.Login Error]: " + valido + " " +desc_error );
                
            }
        } catch(JDOMException mfue) {            
            m_log.error("[MalformedURLException]: ", mfue);
            retorno=-40;
        } catch(MalformedURLException mfue) {            
            m_log.error("[MalformedURLException]: ", mfue);
            retorno=-41;
        } catch(IOException ioe) {
            m_log.error("[IOException]: ", ioe);
            retorno=-42;
//        } catch (Exception e) {
            //try { em.getTransaction().rollback(); } catch (Exception e2) { }
//            m_log.error("[Arkarena.Login]: ", e);
        }

        if ( huc != null) {
            huc.disconnect();
        }
        return retorno;
    }
    
    String getNickRemoto() {
        return m_nick_remoto;
    }

    Usuario getUsuarioLogado() {
        return m_usuario;
    }
    
    
    // Retorno:
    // -10: el nick ya existe
    // -11: Turquia no existe
    // -12: Region Arkarena no existe
    // -13: No existen parametros
    // -14: No existe nick
    int nuevoUsuario ( EntityManager em, String p_remote_nick,
                       String p_email, Integer p_arkarena_id, 
                       HttpServletRequest request, PartnerUsuario  pu ){
        int retorno = -1;
        Usuario         usuario ;
        Usuario         u       ;
        Pais            pais    ;
        Region          region  ;
        String          nick_deseado;
        
        try {
            if ( request == null ) {
                m_log.error(" NO HAY REQUEST ARKARENA "  );                                
                return -13;
            }
            if (request.getParameter("nick")!= null ) {
                // 14/05/2013 Para que tome los caracteres turcos
                // nick_deseado = request.getParameter("nick");
                nick_deseado = URLDecoder.decode(request.getParameter("nick"),"UTF-8");                                                            
                m_log.debug(" nick_deseado " + nick_deseado  );                
            } else {
                m_log.error(" NO HAY NICK DESEADO ARKARENA "  );                                
                return -14;               
            }
            
            try {
                Query q = em.createNamedQuery("Pais.findById");
                q.setParameter("id", "TR");
                pais = (Pais)q.getSingleResult();
            } catch ( NoResultException nores) {
                    m_log.error("[Arkarena.nuevoUsuario.Turkey.no.Existe]: ");
                    return -11;
            }

            try {
                Query q = em.createNamedQuery("Region.findById");
                q.setParameter("id", (short)4);
                region = (Region)q.getSingleResult();
            } catch ( NoResultException nores) {
                    m_log.error("[Arkarena.Region.Arkarena.no.Existe]: ");
                    return -12;
            }
            
            // buscamos si existe el nick
            try {
                Query q = em.createNamedQuery("Usuario.findByNick");

                q.setParameter("nick", nick_deseado);
                u = (Usuario)q.getSingleResult();

                // ya existe el nick
                if ( u != null ) {
                    m_log.error("[Arkarena.nuevoUsuario.Nick.Duplicado]: "+ nick_deseado);
                    return -10;
                }
                
            } catch ( NoResultException nores) {

                // Creamos el usuario
                usuario = new Usuario();

                usuario.setAdmin    (0);
                usuario.setCreditos (0);
                usuario.setEmail    (p_email);
                usuario.setPais     (pais);
                usuario.setIdiomaId ("EN");
                usuario.setNick(nick_deseado.toLowerCase());
                usuario.setNickMostrar(nick_deseado);
                usuario.setOrigenId (4);
                usuario.setPassword ("");
                usuario.setPuntos   (0);
                usuario.setRegion   (region); 
                usuario.setReputacion(99);
                usuario.setRobinson (2);
                usuario.setStatus   (1);
                Date now = new Date();
                usuario.setfAdmision(now);
                usuario.setfAlta(now);
                //usuario.setfEula(null);
                //usuario.setfNacimiento(null);
                usuario.setfUltimo(now);
                
                em.persist(usuario);
                
                //pu = new PartnerUsuario();
                pu.setPartnerId( (short)2);
                pu.setRemoteId(p_arkarena_id);
                pu.setRemoteEmail(p_email);
                pu.setRemoteNick(p_remote_nick);
                pu.setUsuario(usuario);
                
                em.persist(pu);
                retorno=0;
            }            
        } catch (Exception e) {
            try { em.getTransaction().rollback(); } catch (Exception e2) { }
            m_log.error("[Arkarena.Login]: ", e);
            
            Util.anidadas( e, "[Arkarena.Login.NestedException]: ");
        }
        return retorno;        
    }
}
